/*	Brian Kirkpatrick
	String Dictionary class
	Begun 6/30/2010
*/

#include "stringDict.h"

// --- Constructors --- //

stringDict::stringDict() {
	// Create blank dictionary (size 0, no entries)
	size = 0;
	keys = NULL;
	values = NULL;
}

stringDict::stringDict(stringDict &sd) {
	// Deep copy values from sd
	size = sd.size;
	keys = new string[size];
	values = new string[size];
	for (int i = 0; i < size; i++) {
		keys[i] = sd.getKey(i);
		values[i] = sd.getValue(i);
	}
}

stringDict::~stringDict() {
	// Check to destroy pointer arrays for keys, values
	if (keys != NULL) {
		delete[] keys;
		keys = NULL;
	}
	if (values != NULL) {
		delete[] values;
		values = NULL;
	}
}

// --- Operators --- //

string stringDict::operator[](int ndx) {
	// Use array notation to return value at given index
	return getValue(ndx);
}

string stringDict::operator[](string key) {
	// Use array notation to return value with given key
	return get(key);
}

stringDict & stringDict::operator=(const stringDict &operand) {
	if (keys != NULL) {
		delete[] keys;
		keys = NULL;
	}
	if (values != NULL) {
		delete[] values;
		values = NULL;
	}

	size = operand.size;
	keys = new string[size];
	values = new string[size];

	for (int i = 0; i < size; i++) {
		keys[i] = operand.keys[i];
		values[i] = operand.values[i];
	}

	return *this;
}

// --- Methods --- //

void stringDict::print() {
	// Display dictionary in PHP-like format (key=>"value"), bracketed
	printf("{");
	for (int i = 0; i < size; i++) {
		if (i + 1 == size) {
			printf("%s=>\"%s\"", keys[i].c_str(), values[i].c_str());
		} else {
			printf("%s=>\"%s\", ", keys[i].c_str(), values[i].c_str());
		}
	}
	printf("}");
}

void stringDict::set(string key, string value) {
	// Sets entry 'key' to 'value'
	if (size == 0) {
		// Dictionary is blank; create initial entry
		size++;
		keys = new string[size];
		values = new string[size];
		keys[0] = key;
		values[0] = value;
	} else {
		int loc = find(key);
		if (loc < 0) {
			// New entry
			// Back up old list
			int oldSize = size;
			string * oldKeys = keys;
			string * oldValues = values;

			// Create new list
			size++;
			keys = new string[size];
			values = new string[size];

			// Insert in proper location
			bool isInserted = false;
			for (int i = 0; i < oldSize; i++) {
				if (oldKeys[i] < key) {
					keys[i] = oldKeys[i];
					values[i] = oldValues[i];
				} else {
					if (!isInserted) {
						keys[i] = key;
						values[i] = value;
						isInserted = true;
					}
					keys[i+1] = oldKeys[i];
					values[i+1] = oldValues[i];
				}
			}
			if (!isInserted) {
				// New entry is last entry
				keys[size-1] = key;
				values[size-1] = value;
			}
		} else {
			// Replace old entry
			values[loc] = value;
		}
	}
}

int stringDict::find(string key) {
	// Returns index of entry with given key, or -1 if entry does not exist; bisection search assumes sorted key array
	int left = 0; int right = size-1; int mid = (left + right) / 2;
	while (getKey(mid) != key) {
		if (getKey(left) == key) {
			return left;
		} else if (getKey(right) == key) {
			return right;
		} else if (right - left <= 1) {
			// Stop looking; it's not here
			return -1;
		} else if (getKey(mid) < key) {
			// Look right
			left = mid;
		} else if (key < getKey(mid)) {
			// Look left
			right = mid;
		} // ELSE case is break condition
		mid = (left + right) / 2;
	}
	return mid;
}

bool stringDict::inDict(string value) {
	// Returns true if value is present
	for (int i = 0; i < size; i++) {
		if (getValue(i) == value) return true;
	}
	return false;
}

string stringDict::get(string key) {
	// Returns value with given key
	int loc = find(key);
	return loc == -1 ? "" : values[loc];
}

string stringDict::getKey(int ndx) {
	// Returns key at given index
	if (ndx < size && ndx >= 0) {
		return keys[ndx];
	} else {
		return "";
	}
}

string stringDict::getValue(int ndx) {
	// Returns value at given index
	if (ndx < size && ndx >= 0) {
		return values[ndx];
	} else {
		return "";
	}
}

int stringDict::getSize() {
	return size;
}
